/******************************************************************************
 *      Mestrado em Ciência da Computação - UFMS
 *		Redes de Computadores - Prof. Dr. Ronaldo Alves Ferreira
 *		Alunos: Geraldo Landre, Marcel Tolentino, Vinícius Bueno
 *****************************************************************************/
/* tcpsynrcvd.c - tcpsynrcvd */

#include "tcpfms.h"
#include "tcb.h"
#include "tcp.h"
#include "port.h"

/*------------------------------------------------------------------------
 *  tcpsynrcvd -  do SYN_RCVD state input processing
 *------------------------------------------------------------------------
 */
int tcpsynrcvd(struct tcb *ptcb, struct udp *pudp)
{
	//struct	ip	*pip = (struct ip *)pep->ep_data;
	struct	tcp	*ptcp = (struct tcp*)(pudp->udp_data);
	struct	tcb	*pptcb;

	if (ptcp->tcp_code & TCPF_RST) {
		TcpAttemptFails++;
		if (ptcb->tcb_pptcb != 0)
			return tcbdealloc(ptcb);
		else
			return tcpabort(ptcb, TCPE_REFUSED);
	}
	if (ptcp->tcp_code & TCPF_SYN) {
		TcpAttemptFails++;
		tcpreset(pudp);
		return tcpabort(ptcb, TCPE_RESET);
	}
	if (tcpacked(ptcb, pudp) == SYSERR)
		return OK;
	if (ptcb->tcb_pptcb != 0) {		/* from a passive open	*/
		pptcb = ptcb->tcb_pptcb;
		if (sem_wait(&(pptcb->tcb_mutex)) != OK) {
			TcpAttemptFails++;
			tcpreset(pudp);
			return tcbdealloc(ptcb);
		}
		if (pptcb->tcb_state != TCPS_LISTEN) {
			TcpAttemptFails++;
			tcpreset(pudp);
			sem_post(&(pptcb->tcb_mutex));
			return tcbdealloc(ptcb);
		}

	    	if (port_countmsg(pptcb->tcb_listenq) >= pptcb->tcb_lqsize) {
			TcpAttemptFails++;
			tcpreset(pudp);
			sem_post(&(pptcb->tcb_mutex));
			return tcbdealloc(ptcb);
		}
                port_sendmsg(pptcb->tcb_listenq, ptcb->tcb_dvnum);
		//psend(pptcb->tcb_listenq, ptcb->tcb_dvnum);
		sem_post(&(pptcb->tcb_mutex));
	} else					/* from an active open	*/
		sem_post(&(ptcb->tcb_ocsem));
	TcpCurrEstab++;
	ptcb->tcb_state = TCPS_ESTABLISHED;
	tcpdata(ptcb, pudp);
	if (ptcb->tcb_flags & TCBF_RDONE)
		ptcb->tcb_state = TCPS_CLOSEWAIT;
        printf("[tcpsynrcvd] TCPS_ESTABLISHED: %d\n", ptcb->tcb_dvnum);
	return OK;
}
